#ifndef LIBCO_CONCURRENT_H
#define LIBCO_CONCURRENT_H

#include <deque>
#include <optional>
#include "coroutine.hpp"
#include "mutex.hpp"
#include "util.h"

namespace libco {
    
/**
 * @brief 协程任务队列
 *  
 */
class TaskQueue {
public:
    /**
     * @brief 构造函数
     * 
     * @param limit 默认为0，表示队列容量无限大。 
     */
    TaskQueue(size_t limit = 0);

    /**
     * @brief 阻塞式push,push_back
     */
    void push(Coroutine::ptr elem);

    /**
     * @brief 阻塞式push,push_front
     */
    void push_front(Coroutine::ptr elem);

    /**
     * @brief 阻塞式pop
     * 
     * @return 返回队首元素
     * 
     * @note 队列为空时会一直阻塞
     */
    Coroutine::ptr pop();

    /**
     * @brief 查看队列头部元素
     */
    std::optional<Coroutine::ptr> top();

    /**
     * @brief 非阻塞式push
     * 
     * @return 队列未满时push成功，返回true; 否则返回false
     */
    bool try_push(Coroutine::ptr elem);
    /**
     * @brief 无阻塞push n个元素
     * 
     * @param elems 保存push元素的原数组
     * @param n 尝试push的元素最大数量
     * @return size_t 成功push的元素数量
     */
    size_t try_push_n(std::vector<Coroutine::ptr>& elems, size_t n);

    /**
     * @brief push 所有元素
     * 
     * @param elems 保存push元素的原数组
     */
    void push_all(std::vector<Coroutine::ptr>& elems);

    /**
     * @brief 无阻塞pop n个元素
     * 
     * @param elems 保存pop元素的结果数组
     * @param n 尝试pop的元素最大数量
     * @return size_t 成功pop的元素数量
     */
    size_t try_pop_n(std::vector<Coroutine::ptr>& elems, size_t n);

    size_t try_push_all(std::vector<Coroutine::ptr>& elems);

    /**
     * @brief 无阻塞pop 所有元素
     * 
     * @param elems 保存pop元素的结果数组
     * @return size_t 成功pop的元素数量
     */
    size_t try_pop_all(std::vector<Coroutine::ptr>& elems);

    /**
     * @brief 非阻塞式pop
     * 
     * @return 队列非空时pop成功，返回队首元素; 否则返回是std::nullopt
     */
    std::optional<Coroutine::ptr> try_pop();

    void lock();
    void unlock();
    size_t tasks();

protected:
    typedef libco::ScopedLockImpl<Mutex> Lock;

    std::deque<Coroutine::ptr> m_que;
    Mutex m_mutex;
    size_t m_limit;
    ConditionVariable m_cv_notfull;
    ConditionVariable m_cv_notempty;
};

/**
 * @brief 协程锁，调度策略介于互斥锁和自旋锁之间
 * 
 * @note
 */
class CoMutex {

private:
    /// 原子状态
    volatile std::atomic_flag m_locked;
    /// 是否有coroutine处于饥饿等待状态
    std::atomic<bool> m_starving = false;
    /// 阻塞状态
    TaskQueue m_waiting_que;
public:
    /// 局部锁
    typedef ScopedLockImpl<CoMutex> Lock;

    CoMutex();

    void lock();
    void lockslow();

    void unlock();
};

class WaitGroup {
private:
    int m_count = 0;
    Mutex m_mutex;
    ConditionVariable m_cv;
public:
    void add();
    void done();
    void wait();
};

}

#endif // LIBCO_CONCURRENT_H